require 'classes'
require 'threads'
require 'networking'

------------

-- Message factory
class("Messenger", Object)

messageTargets = {
    client = 0x01, -- message is to be sent to clients
    server = 0x02, -- message is to be sent to the server
    both   = 0x03  -- message is for servers and clients
}

-- the One True Message Type Source
messages = {}

function Messenger:_construct(...)    
    self.target = nil
    self.interface = nil
    self:superClass():_construct(...)
end

-- Set the mode that the messenger will be operating in
function Messenger:setTarget(target)
    self.target = target
end

-- Create a group of messages
function Messenger:registerGroup(parentGroup, name)

    if (name == nil) then
        error("Attempted to register a message group with no name")
    end

    if (parentGroup == nil) then
        parentGroup = messages
    end
    
    if (parentGroup[name] ~= nil) then
        warn("Attempted to register a group named " .. name .. " when it already existed")
        return
    end
    
    -- all checks passed? awesome
    local newGroup = {}
    parentGroup[name] = newGroup
    
    newGroup._groupName = name
    newGroup._parentGroup = parentGroup
    
    return parentGroup[name]
end

-- register a type of message in a group
function Messenger:registerMessage(parentGroup, descriptorTable)
    if (parentGroup == nil) then
        parentGroup = messages
    end
    
    if (descriptorTable == nil) then
        error("Invalid message type")
    end
    
    if (parentGroup[name] ~= nil) then
        warn("Attempted to register a message named " .. name .. " when it already existed")
        return
    end
    
    -- and now we register the message
    parentGroup[descriptorTable.name] = descriptorTable
    
    descriptorTable.fullName = self:describeGroup(parentGroup) .. descriptorTable.name
    
    if (descriptorTable.target == nil) then
        -- by default, assume a message is meant for everyone
        descriptorTable.target = messageTargets.both
    end
    
end

function Messenger:setNetworkInterface(interface)
    self.interface = interface
    interface:setDelegate(self)
    
    if (interface:isa(Client)) then
        -- we're a client! set target appropriately
        self:setTarget(messageTargets.server)
    elseif (interface:isa(Server)) then
        -- to the clients we go
        self:setTarget(messageTargets.client)
    end
end

function Messenger:describeGroup(group)
    local description = ""
    local currentGroup = group
    -- step back through the tree and construct the description
    
    while (currentGroup) do
        if (currentGroup._groupName ~= nil) then
            description = currentGroup._groupName .. "." .. description
        end
        currentGroup = currentGroup._parentGroup
    end
    return description
end

-- returns a clone of a prototype message
-- so it can be modified and sent out
function Messenger:prepareMessage(prototype)
    return clone(prototype)
end

function Messenger:messageReceived(data)
    --print(self.interface:className() .. " got a message: " .. data.message.fullName)
end

function Messenger:send(message)
    --print(tostring(self) .. " sending " .. message.fullName)
    
    if message.target ~= messageTargets.both and self.target ~= message.target then
        print (message.target .. ": Discarding packet " .. message.fullName)
        return -- discard packets that we'd be sending to ourself
    end
    
    --pause()
    
    --print(table.show(message))
    
    local messagePacket = {
        command = NetworkCommands.message,
        message = message
        }
    
    if self.target == messageTargets.client then
        self.interface:sendToAllClients(messagePacket)
    elseif self.target == messageTargets.server then
        self.interface:sendDataToPeer(messagePacket)
    end
    
end

----------
